﻿//******************** WHUI控件库***线条图表控件WHLineChart使用说明********************************************
//************1.目前只支持单条 曲线或折线 显示，LineStyle 指定
//************2.支持填充区域渐变，支持是否填充，支持是否显示用户输入的坐标点，具体看说明
//************3.首先使用  whLineChart1.ClearAllUserValues();清屏清理用户输入的坐标点，不然会乱屏，如果保存坐标点用户负责保存！
//************4.然后使用  AddUserValue(0.1f, 0.55f, "55%");添加用户自定义坐标点 注意：0.1f为X轴长度的坐标比例，0.55f即用户坐标点
//************4.   数值相当于Y轴长度的比例，“55%”是用户要显示在图表上的字符串
//************5.  最后可以用   Invalidate 或者 Refresh 强制重绘来刷出图表
//************如有疑问联系 微信：13781551704******qq：453983184 ******************
//**********************If you use this code, please keep this note.
//****************** * 如果您使用此代码，请保留此说明。*****************************************************************************************

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace WHControlLib.Controls.Chart
{
    /// <summary>
    /// 线条图表控件
    /// </summary>
    public partial class WHLineChart : WHbaseScaleChart
    {
        public WHLineChart()
        {
            ////背景定义为透明色   
            SetStyle(ControlStyles.SupportsTransparentBackColor, true);
            BackColor = Color.Transparent;
            InitializeComponent();
        }
      public  enum UserLineStyleType { Curve,line};
       public  enum UserPointStyleType { Circle,Squite};
        List<PointF> DispayUserPoints = new List<PointF>();

        #region 属性定义
        private float _userPointWidth = 5.0f;
        [Category("A我的线图"), Description(" 画用户点的大小，默认，5.0f不能小于1.0f"), Browsable(true)]
        public float UserPointWidth
        {
            get { return _userPointWidth; }
            set
            {
                if (value<1.0f)
                {
                    value = 1.0f;
                }
                else
                _userPointWidth = value;

                this.Invalidate();
                
            }
        }

        private Color _userPointPenColor = Color.Blue;
        [Category("A我的线图"), Description(" 用户点的颜色，默认，蓝色"), Browsable(true)]
        public Color UserPointPenColor
        {
            get { return _userPointPenColor; }
            set
            {

                _userPointPenColor = value;

                this.Invalidate();
            }
        }
        private Color _userPointFillColor = Color.Orange;
        [Category("A我的线图"), Description(" 用户点的填充颜色，默认，橙色"), Browsable(true)]
        public Color UserPointFillColor
        {
            get { return _userPointFillColor; }
            set
            {

                _userPointFillColor = value;

                this.Invalidate();
            }
        }
        private bool _isShowUserPoint = true;
        [Category("A我的线图"), Description(" 是否显示用户定义的点，默认 true"), Browsable(true)]
        public bool IsShowUserPoint
        {
            get { return _isShowUserPoint; }
            set
            {

                _isShowUserPoint = value;

                this.Invalidate();
            }
        }
        private bool _isFillUserPoint = true;
        [Category("A我的线图"), Description(" 是否填充用户定义的点的内部，默认 true"), Browsable(true)]
        public bool IsFillUserPoint
        {
            get { return _isFillUserPoint; }
            set
            {

                _isFillUserPoint = value;

                this.Invalidate();
            }
        }
        private float _userPointPenwidth=1.5f  ;
          
        [Category("A我的线图"), Description(" 定义的点的外圈线宽，默认 1.5f"), Browsable(true)]
        public float UserPointPenwidth
        {
            get { return _userPointPenwidth; }
            set { _userPointPenwidth = value; this.Invalidate(); }
        }
        private float _userLinePenwidth = 2.5f;

        [Category("A我的线图"), Description(" 定义的连线的线宽，默认 2.5f"), Browsable(true)]
        public float UserLinePenwidth
        {
            get { return _userLinePenwidth; }
            set { _userLinePenwidth = value; this.Invalidate(); }

        }
        private Color _userLineColor=Color.Black;
        [Category("A我的线图"), Description(" 定义的连线的线颜色，默认 黑色"), Browsable(true)]
        public Color UserLineColor
        {
            get { return _userLineColor; }
            set { _userLineColor=value; this.Invalidate(); }
        }

        private bool _isShowUserPointLine = true;
        [Category("A我的线图"), Description(" 是否显示用户定义的点的连线，默认 true"), Browsable(true)]
        public bool IsShowUserPointLine
        {
            get { return _isShowUserPointLine; }
            set
            {

                _isShowUserPointLine = value;

                this.Invalidate();
            }
        }

        private bool _isFillLineRegion= true;
        [Category("A我的线图"), Description(" 是否填充用户线图底部区域，默认 true"), Browsable(true)]
        public bool IsFillLineRegion
        {
            get { return _isFillLineRegion; }
            set
            {

                _isFillLineRegion = value;

                this.Invalidate();
            }
        }

        private bool _isUseTwoColorFillLineRegion = true;
        [Category("A我的线图"), Description(" 是否允许用渐变色填充用户线图底部区域，默认 true"), Browsable(true)]
        public bool IsUseTwoColorFillLineRegion
        {
            get { return _isUseTwoColorFillLineRegion; }
            set
            {

                _isUseTwoColorFillLineRegion = value;

                this.Invalidate();
            }
        }
        private Color _firstFillRegionColor = Color.Yellow;
        [Category("A我的线图"), Description(" 第一种线图填充的颜色，默认，黄色"), Browsable(true)]
        public Color FirstFillRegionColor
        {
            get { return _firstFillRegionColor; }
            set
            {

                _firstFillRegionColor = value;

                this.Invalidate();
            }
        }
        private Color _secondFillRegionColor = Color.Red;
        [Category("A我的线图"), Description(" 第二种线图填充的颜色，默认:红色"), Browsable(true)]
        public Color SecondFillRegionColor
        {
            get { return _secondFillRegionColor; }
            set
            {

                _secondFillRegionColor = value;

                this.Invalidate();
            }
        }

        private UserPointStyleType _userPointStyle=UserPointStyleType.Circle;
        [Category("A我的线图"), Description(" 用户点的显示样式，默认:实心圆"), Browsable(true)]
        public UserPointStyleType UserPointStyle
        {
            get { return _userPointStyle; }
            set { _userPointStyle = value; this.Invalidate(); }
        }

        private UserLineStyleType _userLineStyle = UserLineStyleType.Curve;
        [Category("A我的线图"), Description(" 用户绘制的线条样式，默认:曲线"), Browsable(true)]
        public UserLineStyleType UserLineStyle
        {
            get { return _userLineStyle; }
            set { _userLineStyle = value; this.Invalidate(); }
        }
        //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
        Rectangle MyRulerRect = new Rectangle();
        Rectangle myrect = new Rectangle();
        #endregion
        protected override void OnPaint(PaintEventArgs e)
        {
           //base.OnPaint(e);
            Graphics myg= e.Graphics;
          
            myg.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
            myg.CompositingQuality = System.Drawing.Drawing2D.CompositingQuality.HighQuality;
            myrect = this.ClientRectangle; 
            MyRulerRect = GetRulerRect(myrect,this.RulerBodyBlank);
            if (IsShowUserPointLine)
            {
            DrawUserLine(myg, UserPoints);
            }
           
            if (IsShowUserPoint)
            {
             DrawUserValuePoint(myg, MyRulerRect);
            }
            // 屏蔽了父类的话尺子的方法，改在子类里实现，目的是填充会覆盖父类画的直线，还想利用父类做单独控件使用
             //后期感觉父类不需要可隐藏父类控件，目前不做改变，需做屏蔽父类onpaint事件，
             // 其坐标转换在父类onpianbackgrond中，如有错误也可放在子类中
            DrawHorRulerBody(myg, MyRulerRect);
            DrawVerRulerBody(myg, MyRulerRect);
            //每次作图完毕需要清除用户的作图点的数组 即 （用户数据缓存），用户自己保存需要作图点，目前本控件不加入该功能

            if (IsShowUserValueMsg)
            {  
                DispayUserPoints.Clear();
               

                foreach (var point in UserPoints)
                {
                    PointF p = new PointF();
                    p = point;
                    DispayUserPoints.Add(p);
                }

                DrawUserValueMsg(myg, DispayUserPoints);
            }

       


        }

        void DrawUserValuePoint(Graphics Myg,Rectangle RulerRect)
        {
            //先确定每个点的具体坐标
       
            if (UserValues.Count>0)
               
            {
            
          
                    switch (UserPointStyle)
                    {
                        case UserPointStyleType.Circle:
                        foreach (var item in UserPoints)
                        {
                            //计算每个点相对于比例尺矩形区域的坐标
                            RectangleF r = new RectangleF();
                            r.Location = new PointF(item.X - UserPointWidth / 2, item.Y - UserPointWidth / 2);
                            r.Width = UserPointWidth ;
                            r.Height = UserPointWidth;

                            if (_isFillUserPoint)
                            {
                                using (SolidBrush Pbrush = new SolidBrush(UserPointFillColor))
                                {
                                    Myg.FillEllipse(Pbrush, r);
                                }
                            }

                            using (Pen pen = new Pen(UserPointPenColor, UserPointPenwidth))
                            {
                                Myg.DrawEllipse(pen, r);
                            }
                        }
                            break;
                        case UserPointStyleType.Squite:
                        foreach (var item in UserPoints)
                        {  
                            //计算每个点相对于比例尺矩形区域的坐标
                            Rectangle r = new Rectangle();
                            r.Location = new Point((int)(item.X - UserPointWidth / 2 ), (int)(item.Y - UserPointWidth / 2 ));
                            r.Width = (int)UserPointWidth;
                            r.Height = (int)UserPointWidth;

                            if (_isFillUserPoint)
                            {
                                using (SolidBrush Pbrush = new SolidBrush(UserPointFillColor))
                                {
                                    Myg.FillRectangle(Pbrush, r);
                                }
                            }

                            using (Pen pen = new Pen(UserPointPenColor, UserPointPenwidth))
                            {
                                Myg.DrawRectangle(pen, r);

                            }
                        }
                            break;
                        default:
                            break;
                    }
                    
                }
            
          }
     
        void DrawUserLine(Graphics Myg,List<PointF> UserPoints)
        {
            if (UserPoints.Count > 1)
            { 
                //计算所得到图形的颜色填充区域
                //计算线图的填充形状
                GraphicsPath graphicPath = new GraphicsPath();
                switch (UserLineStyle)
                {
                    case UserLineStyleType.Curve:
                        graphicPath.AddCurve(UserPoints.ToArray());
                        break;
                    case UserLineStyleType.line:
                        graphicPath.AddLines(UserPoints.ToArray());
                        break;
                    default:
                        break;
                }
             
               
         
         
                      //获得填充图形的在x轴和Y轴上的 起点和终点
                PointF Pstart = new PointF(UserPoints[0].X, MyRulerRect.Bottom );
                PointF Pend = new PointF(UserPoints[UserPoints.Count - 1].X , MyRulerRect.Bottom );
                graphicPath.AddLine(UserPoints[UserPoints.Count - 1], Pend);
                graphicPath.AddLine(Pstart, Pend);
                graphicPath.AddLine(Pstart, UserPoints[0]);

                graphicPath.CloseFigure();
              
                
                //计算画刷的填充矩形范围
                Rectangle BrushRect = new Rectangle();
                int maxY = MyRulerRect.Bottom;
                foreach (var item in UserPoints)
                {
                    if (item.Y < maxY)
                        maxY = (int)item.Y;
                }
                BrushRect.Location = new Point((int)(UserPoints[0].X ), (int)(maxY - UserPointPenwidth/2));
                
                
                BrushRect.Width = (int)(Pend.X - Pstart.X +RulerBodyWidth);
                BrushRect.Height = (int)(MyRulerRect.Bottom-RulerBodyWidth - maxY + UserPointPenwidth );
                //根据选定的线条样式划线

                if (IsFillLineRegion)
                {
                    if (IsUseTwoColorFillLineRegion)

                    {

                        using (LinearGradientBrush bs = new LinearGradientBrush(BrushRect, SecondFillRegionColor,FirstFillRegionColor , LinearGradientMode.Vertical))
                        {
                            bs.WrapMode=WrapMode.TileFlipX;
                            Myg.FillPath(bs, graphicPath);
                        }
                    }
                    else
                    {
                        using (SolidBrush bs = new SolidBrush(FirstFillRegionColor))
                        {
                            Myg.FillPath(bs, graphicPath);
                        }
                    }


                }
                //画出连接各个用户坐标点之间的连线

                using (Pen linePen = new Pen(UserLineColor, UserLinePenwidth))
                {
                    switch (UserLineStyle)
                    {
                        case UserLineStyleType.Curve:
                            Myg.DrawCurve(linePen, UserPoints.ToArray());
                            break;
                        case UserLineStyleType.line:
                            Myg.DrawLines(linePen, UserPoints.ToArray());
                            break;
                        default:
                            break;
                    }

                }

          
     
                }
          
          
            }
        
           void DrawUserValueMsg(Graphics myg, List<PointF> userPoints)
        {
            if (userPoints.Count > 0)
              
            {
          
                for (int i = 0; i < userPoints.Count; i++)
                {
                  if (UserValues[i].UserValueMsg!=null&&UserValues[i].UserValueMsg!="")
                     {     
                        PointF p = new PointF();
                        p.X = userPoints[i].X - myg.MeasureString(UserValues[i].UserValueMsg, UserValueMsgFont).Width/2;
                        p.Y = userPoints[i].Y - UserPointWidth / 2 - 0 - myg.MeasureString(UserValues[i].UserValueMsg, UserValueMsgFont).Height;
                       if (p.Y<0)
                        {
                        p.Y = 0f;
                        }
                        if (p.X<= RulerBodyWidth + RulerBodyBlank)
                        {
                            p.X = 0f+RulerBodyWidth+RulerBodyBlank;
                        }
                    myg.DrawString(UserValues[i].UserValueMsg,UserValueMsgFont,new SolidBrush(UserValueMsgColor),p);
                    }


                }


            }
        
        
        
        }
          

      
 /////////////////////////////////////////////////////

    }
}
